﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json.Serialization;
using Sustainalytics.Reporting.BusinessLogic;
using Sustainalytics.ReportGenerator.BL;
using Sustainalytics.Entities;

namespace Sustainalytics.Reporting.BusinessLogic
{
    public class ReportingServiceClient : IDisposable
    {
        private readonly Uri _uri;
        private readonly HttpClient _client;
        private readonly JsonMediaTypeFormatter _jsonMediaTypeFormatter;

        public ReportingServiceClient(Uri uri)
        {
            if (uri == null)
                throw new ArgumentNullException("uri");

            _uri = uri;

            _client = new HttpClient() ;
            _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            _jsonMediaTypeFormatter = new JsonMediaTypeFormatter
            {
                SerializerSettings =
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                }
            };
        }

        public async Task<ExecutionResult> GetEsgReport(Guid companyId, Guid esgProfileId)
        {
            if (companyId == null)
                throw new ArgumentNullException("companyId");

            try
            {
                var requestUri = string.Format("{0}/company/{1}/esgReport/{2}", _uri, companyId, esgProfileId);

                var result = await _client.GetAsync(requestUri);

                if (result.IsSuccessStatusCode)
                {
                    return await result.Content.ReadAsAsync<ExecutionResult>(_jsonMediaTypeFormatter.Yield());
                }

                var error = await result.Content.ReadAsAsync<ExecutionError>(_jsonMediaTypeFormatter.Yield());

                throw new ReportingServiceClientException()
                {
                    ErrorStatusCode = error == null ? 0 : error.ErrorStatusCode,
                    ErrorMessage = error == null ? string.Empty : error.ErrorMessage,
                    HttpStatusCode = result.StatusCode,
                };
            }
            catch (HttpRequestException httpRequestException)
            {
                throw new ReportingServiceClientException("Failed to execute the raport", httpRequestException);
            }
        }

        public async Task<ExecutionResult> GetControversyReport(Guid companyId)
        {
            if (companyId == null)
                throw new ArgumentNullException("companyId");

            try
            {
                var requestUri = string.Format("{0}/company/{1}/controversyReport", _uri, companyId);

                var result = await _client.GetAsync(requestUri);

                if (result.IsSuccessStatusCode)
                {
                    return await result.Content.ReadAsAsync<ExecutionResult>(_jsonMediaTypeFormatter.Yield());
                }

                var error = await result.Content.ReadAsAsync<ExecutionError>(_jsonMediaTypeFormatter.Yield());

                throw new ReportingServiceClientException()
                {
                    ErrorStatusCode = error == null ? 0 : error.ErrorStatusCode,
                    ErrorMessage = error == null ? string.Empty : error.ErrorMessage,
                    HttpStatusCode = result.StatusCode,
                };
            }
            catch (HttpRequestException httpRequestException)
            {
                throw new ReportingServiceClientException("Failed to execute the raport", httpRequestException);
            }
        }

        public async Task<ExecutionResult> ExecuteReport(PdfReportParameters reportParameters)
        {
            if (reportParameters == null)
                throw new ArgumentNullException("reportParameters");

            try
            {
                var result = await _client.PostAsync(_uri, reportParameters, _jsonMediaTypeFormatter);
                
                if (result.IsSuccessStatusCode)
                {
                    return await result.Content.ReadAsAsync<ExecutionResult>(_jsonMediaTypeFormatter.Yield());
                }

                var error = await result.Content.ReadAsAsync<ExecutionError>(_jsonMediaTypeFormatter.Yield());
                
                throw new ReportingServiceClientException()
                {
                    ErrorStatusCode = error == null ? 0 : error.ErrorStatusCode,
                    ErrorMessage = error == null ? string.Empty : error.ErrorMessage,
                    HttpStatusCode = result.StatusCode,
                };
            }
            catch(HttpRequestException httpRequestException) 
            {
                throw new ReportingServiceClientException("Failed to execute the raport", httpRequestException);
            }
        }

        public async Task<ExecutionResult> ExecuteBulkPdfReports(ReportOptions reportOptions)
        {
            if (reportOptions == null)
                throw new ArgumentNullException("reportOptions");

            try
            {
                var requestUri = string.Format("{0}/reportManager", _uri);

                var result = await _client.PostAsync(requestUri, reportOptions, _jsonMediaTypeFormatter);

                if (result.IsSuccessStatusCode)
                {
                    return await result.Content.ReadAsAsync<ExecutionResult>(_jsonMediaTypeFormatter.Yield());
                }

                var error = await result.Content.ReadAsAsync<ExecutionError>(_jsonMediaTypeFormatter.Yield());

                throw new ReportingServiceClientException()
                {
                    ErrorStatusCode = error == null ? 0 : error.ErrorStatusCode,
                    ErrorMessage = error == null ? string.Empty : error.ErrorMessage,
                    HttpStatusCode = result.StatusCode,
                };
            }
            catch (HttpRequestException httpRequestException)
            {
                throw new ReportingServiceClientException("Failed to execute the raport", httpRequestException);
            }
        }

        public void Dispose()
        {
            if (_client != null)
                _client.Dispose();
        }
    }
}
